<template>
  <el-dialog :model-value="showKeyWordVisible" title="选择关键字" width="500" @close="closeDialog" :close-on-click-modal="false">
    <div
      ref="container"
      class="text-container"
      @mousedown="startSelection"
      @mousemove="onMouseMove"
      @mouseup="endSelection"
    >
      <div
        v-if="dragBox.visible"
        class="selection-box"
        :style="{
          left: dragBox.left + 'px',
          top: dragBox.top + 'px',
          width: dragBox.width + 'px',
          height: dragBox.height + 'px'
        }"
      />

      <span
        v-for="(char, index) in characters"
        :key="index"
        class="char"
        :class="{ selected: isSelected(index) }"
      >
        {{ char }}
      </span>
    </div>

    <template #footer>
      <el-button @click="resetSelection">重置</el-button>
      <el-button @click="closeDialog">取消</el-button>
      <el-button type="primary" @click="handleConfirm">确定</el-button>
    </template>
  </el-dialog>
</template>

<script setup>
  import { ref, computed } from 'vue'

  const props = defineProps({
    text: String,
    showKeyWordVisible: Boolean
  })
  const emit = defineEmits(['closeDialog'])

  const container = ref(null)
  const characters = computed(() => (props.text || '').split(''))

  const selectedRanges = ref([])

  // 拖拽框位置
  const dragBox = ref({
    visible: false,
    startX: 0,
    startY: 0,
    left: 0,
    top: 0,
    width: 0,
    height: 0
  })

  const isDragging = ref(false)

  const startSelection = (e) => {
    isDragging.value = true
    const rect = container.value.getBoundingClientRect()

    dragBox.value.startX = e.clientX
    dragBox.value.startY = e.clientY
    dragBox.value.left = e.clientX - rect.left
    dragBox.value.top = e.clientY - rect.top
    dragBox.value.width = 0
    dragBox.value.height = 0
    dragBox.value.visible = true
  }

  const onMouseMove = (e) => {
    if (!isDragging.value) return
    const rect = container.value.getBoundingClientRect()

    const x = Math.min(e.clientX, dragBox.value.startX)
    const y = Math.min(e.clientY, dragBox.value.startY)
    const width = Math.abs(e.clientX - dragBox.value.startX)
    const height = Math.abs(e.clientY - dragBox.value.startY)

    dragBox.value.left = x - rect.left
    dragBox.value.top = y - rect.top
    dragBox.value.width = width
    dragBox.value.height = height
  }

  const endSelection = () => {
    if (!isDragging.value) return
    isDragging.value = false
    dragBox.value.visible = false

    const containerEl = container.value
    if (!containerEl || characters.value.length === 0) return

    // 获取所有字符元素
    const charElements = containerEl.querySelectorAll('.char')
    if (charElements.length === 0) return

    const containerRect = containerEl.getBoundingClientRect()

    // 计算选中范围对应的字符索引
    let minIndex = characters.value.length
    let maxIndex = -1

    // 框选区域相对于容器的坐标
    const selectionLeft = dragBox.value.left
    const selectionTop = dragBox.value.top
    const selectionRight = dragBox.value.left + dragBox.value.width
    const selectionBottom = dragBox.value.top + dragBox.value.height

    charElements.forEach((charEl, index) => {
      const charElRect = charEl.getBoundingClientRect()

      // 字符元素相对于容器的坐标和尺寸
      const charRelativeLeft = charElRect.left - containerRect.left
      const charRelativeTop = charElRect.top - containerRect.top
      const charRelativeRight = charElRect.right - containerRect.left
      const charRelativeBottom = charElRect.bottom - containerRect.top

      // 检查框选区域是否与当前字符元素重叠
      const isOverlapping = !(
        selectionRight < charRelativeLeft ||
        selectionLeft > charRelativeRight ||
        selectionBottom < charRelativeTop ||
        selectionTop > charRelativeBottom
      )

      if (isOverlapping) {
        minIndex = Math.min(minIndex, index)
        maxIndex = Math.max(maxIndex, index)
      }
    })

    if (minIndex <= maxIndex && minIndex !== characters.value.length && maxIndex !== -1) {
      selectedRanges.value.push({
        start: minIndex,
        end: maxIndex
      })
    }
  }

  const isSelected = (index) => {
    return selectedRanges.value.some(({ start, end }) => index >= start && index <= end)
  }

  const resetSelection = () => {
    selectedRanges.value = []
  }

  const handleConfirm = () => {
    const result = selectedRanges.value.map(({ start, end }) =>
      characters.value.slice(start, end + 1).join('')
    )
    emit('closeDialog', result)
  }

  function closeDialog() {
    emit('closeDialog')
  }
</script>

<style scoped>
  .text-container {
    position: relative;
    display: flex;
    flex-wrap: wrap;
    padding: 10px;
    border: 1px solid #ccc;
    cursor: crosshair;
    user-select: none;
    min-height: 120px;
    box-sizing: border-box;
  }

  .char {
    display: inline-block;
    width: 28px;
    height: 36px;
    line-height: 36px;
    margin: 4px;
    text-align: center;
    border: 1px solid #ddd;
    border-radius: 4px;
    font-size: 16px;
  }

  .char.selected {
    background-color: #409eff;
    color: white;
    border-color: #409eff;
  }

  .selection-box {
    position: absolute;
    background-color: rgba(64, 158, 255, 0.3);
    border: 1px dashed #409eff;
    pointer-events: none;
    z-index: 10;
  }
</style>